{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "782648d7-6ea3-49bc-909c-5eab79bb7bd7",
   "metadata": {},
   "source": [
    "# 处理PDF\n",
    "\n",
    "- pypdf是比较流行的pdf处理库，是pypdf的新版本。\n",
    "- pdfplumber\n",
    "\n",
    "扫描版pdf可能无法读取。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "916f6284-a1db-42e9-b3fe-9937d4e6758b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pypdf\n",
    "path = \"pdf/cet6.pdf\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7f06a36-199b-4fd4-a5dc-86d8bccfb07a",
   "metadata": {},
   "source": [
    "## 从PDF中提取文本\n",
    "\n",
    "pypdf没有办法从 PDF 文档中提取图像、图表或其他媒体，但它可以提取文本，并将其返回为 Python 字符串。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "d6e6d802-ed28-4f74-adb2-1fa9148d5888",
   "metadata": {},
   "outputs": [],
   "source": [
    "reader = pypdf.PdfReader(path)\n",
    "for page in reader.pages[:5]:\n",
    "    print(page.extract_text())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "98fb2a61-2c61-4818-9b0b-ab7cf1f527e1",
   "metadata": {},
   "source": [
    "## 旋转和叠加页面\n",
    "\n",
    "上面的代码中通过创建PdfFileReader对象的方式来读取 PDF 文档，该对象的getPage方法可以获得PDF文档的指定页并得到一个PageObject对象，通过PageObject对象的rotateClockwise和rotateCounterClockwise方法可以实现页面的顺时针和逆时针方向旋转，通过PageObject对象的addBlankPage方法可以添加一个新的空白页"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "eddb3caf-3e12-40d6-a625-a376d4031300",
   "metadata": {},
   "outputs": [],
   "source": [
    "reader = pypdf.PdfReader(path)\n",
    "writer = pypdf.PdfWriter()\n",
    "\n",
    "for no, page in enumerate(reader.pages[:4]):\n",
    "    if no % 2 == 0: \n",
    "        new_page = page.rotate(-90)\n",
    "    else:\n",
    "        new_page = page.rotate(90)\n",
    "    # 添加页面\n",
    "    writer.add_page(new_page)\n",
    "\n",
    "with open('pdf/temp.pdf', 'wb') as file_obj:\n",
    "    # 将所有添加的页面写入文件\n",
    "    writer.write(file_obj)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8929572d-ae2d-4079-a4f4-f24d6e7cfb99",
   "metadata": {},
   "source": [
    "## 加密PDF文件\n",
    "\n",
    "使用PdfFileWrite对象可以为PDF文档加密，如果需要给一系列的PDF文档设置统一的访问口令，使用Python程序来处理就会非常的方便。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "73a16c9f-a213-46e3-9a74-3220156ddd96",
   "metadata": {},
   "outputs": [],
   "source": [
    "reader = pypdf.PdfReader(path)\n",
    "writer = pypdf.PdfWriter()\n",
    "\n",
    "for page in reader.pages[:3]:\n",
    "    writer.add_page(page)\n",
    "\n",
    "# 设置密码\n",
    "writer.encrypt('123456')\n",
    "\n",
    "with open('pdf/temp.pdf', 'wb') as file_obj:\n",
    "    writer.write(file_obj)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8120d8a-c2db-4c6e-874a-99aeff19cb0d",
   "metadata": {},
   "source": [
    "## 批量添加水印\n",
    "\n",
    "上面提到的PageObject对象还有一个名为mergePage的方法，可以两个 PDF 页面进行叠加，通过这个操作，我们很容易实现给PDF文件添加水印的功能。\n",
    "\n",
    "例如要给pdf文件添加一个水印，我们可以先准备好一个提供水印页面的 PDF 文件，然后将包含水印的PageObject读取出来，然后再循环遍历需要添加水印的文件的每个页，获取到PageObject对象，然后通过mergePage方法实现水印页和原始页的合并"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "b42116e7-06e3-41cf-9e19-082d45f0e8e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "reader1 = pypdf.PdfReader(path)\n",
    "reader2 = pypdf.PdfReader('pdf/watermark.pdf')\n",
    "writer = pypdf.PdfWriter()\n",
    "watermark_page = reader2.pages[0]\n",
    "\n",
    "for page in reader1.pages:\n",
    "    page.merge_page(watermark_page)\n",
    "    writer.add_page(page)\n",
    "\n",
    "with open('pdf/temp.pdf', 'wb') as file_obj:\n",
    "    writer.write(file_obj)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5074f68a-e334-430a-afbe-5a2dfa9fecbd",
   "metadata": {},
   "source": [
    "## 创建PDF文件\n",
    "\n",
    "创建 PDF 文档需要三方库reportlab的支持"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "e4cbb367-203c-4568-bc99-144568b95838",
   "metadata": {},
   "outputs": [],
   "source": [
    "from reportlab.lib.pagesizes import A4\n",
    "from reportlab.pdfbase import pdfmetrics\n",
    "from reportlab.pdfbase.ttfonts import TTFont\n",
    "from reportlab.pdfgen import canvas\n",
    "\n",
    "pdf_canvas = canvas.Canvas('pdf/demo.pdf', pagesize=A4)\n",
    "width, height = A4\n",
    "\n",
    "# 绘图\n",
    "image = canvas.ImageReader('pdf/image.jpeg')\n",
    "pdf_canvas.drawImage(image, 20, height - 395, 250, 375)\n",
    "\n",
    "# 显示当前页\n",
    "pdf_canvas.showPage()\n",
    "\n",
    "# 注册字体文件\n",
    "pdfmetrics.registerFont(TTFont('Font', 'pdf/font.ttf'))\n",
    "\n",
    "# 写字\n",
    "pdf_canvas.setFont('Font', 40)\n",
    "pdf_canvas.setFillColorRGB(0.9, 0.5, 0.3, 1)\n",
    "pdf_canvas.drawString(width // 2 - 120, height // 2, 'Nice to meet you!')\n",
    "\n",
    "# 保存\n",
    "pdf_canvas.save()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
